extern crate clap;
extern crate rand;
extern crate utf8_chars;

use clap::{App, Arg};

use std::fs::File;
use std::io;
use std::io::BufRead;
use std::io::BufReader;
use std::io::IsTerminal;
use std::num::ParseIntError;
use std::task::Context;
use utf8_chars::BufReadCharsExt;

mod demo;

// import the demo module
pub use demo::*;


fn main() {
    let mut filename: String = "".to_string();
    let mut cli_args = parse_cli_args(&mut filename);
    if filename == "" {
        let stdin = io::stdin();
        print_chars_lol(BufRead::new(stdin.lock()).chars().map(|x| x.unwrap()), &mut cli_args, true);
    } else if lolcat_file(&filename, &cli_args).is_err() {
        eprintln!("Error reading file: {}", filename);
    }
}

fn lolcat_file(filename: &str, cli_args: &mut Control) -> Result<(), io::Error> {
    let f = File::open(filename)?;
    let reader = BufReader::new(f);
    print_lines_lol(reader.chars().map(|x| x.unwrap()), cli_args);
    Ok(())
}

fn parse_cli_args(filename: &mut String) -> Control {
    let matches = lolcat_clap_app().get_matches(); //获取命令行参数
    let seed = matches.value_of("seed").unwrap_or("0").parse::<u64>().unwrap_or(0);
    let spread = matches.value_of("spread").unwrap_or("3").parse::<u64>().unwrap_or(3);
    let frequency = matches.value_of("frequency").unwrap_or("1").parse::<u64>().unwrap_or(1);
    if seed = 0.0 {
        seed = rand::random::<f64>() * 10e9;
    };
    *filename = matches.value_of("file").unwrap_or("").to_string();
    let print_color = matches.if_present("face-color") || std::io::stdout().is_terminal();

    let terminal_width: u16 = match terminal_width {
        Ok(width) => width,
        Err(_) => {
            let size = termsize::get();
            match size {
                Some(size) => size.cols,
                None => 0b11111111_11111111,
            }
        }
    };
    let terminal_supports_truecolor = match std::env::var("COLORTERM") {
        Ok(val) => val == "truecolor" || val == "24bit",
        Err(_) => false,
    };
    //定义 一个cat控制结构体
    let mut retval = demo::Control {
        seed,
        spread,
        frequency,
        background_mode: matches.is_present("background"),  //是否使用背景色
        dialup_mode: matches.is_present("dialup"),  //是否使用低速模式
        print_color,
        terminal_width_plus_one: terminal_width.wrapping_add(1), //终端宽度加1
        terminal_supports_truecolor, //终端是否支持truecolor
    };
    if matches.is_present("help") {
        print_rainbow_help(false, &mut retval);
    };
    if matches.is_present("version") {
        print_rainbow_help(true, &mut retval);
    }
    return retval;
}

fn print_rainbow_help(version: bool, control: &mut Control) {
    let app = lolcat_clap_app();
    let mut help = Vec::new();
    if version {
        app.write_version(&mut help).unwrap();
    } else {
        app.write_help(&mut help).unwrap();
    }
    help = String::from_utf8(&help).unwrap();
    print_lines_lol(help.lines(), control);
}

fn lolcat_clap_app() -> App<'static, 'static> {
    App::new("lolcat")
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .arg(
            Arg::with_name("seed")
                .short("s")
                .long("seed")
                .help("A seed for your lolcat. Setting this to 0 randomizes the seed.")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("spread")
                .short("S")
                .long("spread")
                .help("How much should we spread dem colors? Defaults to 3.0")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("frequency")
                .short("f")
                .long("frequency")
                .help("Frequency - used in our math. Defaults to 0.1")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("background")
                .short("B")
                .long("bg")
                .help("Background mode - If selected the background will be rainbow. Default false")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("dialup")
                .short("D")
                .long("dialup")
                .help("Dialup mode - Simulate dialup connection")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("force-color")
                .short("F")
                .long("force-color")
                .help("Force color - Print escape sequences even if the output is not a terminal")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("width")
                .long("terminal-width")
                .help("Terminal width - Set a custom terminal wrapping width, or 0 for unlimited")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("filename")
                .short("i")
                .long("input file name")
                .help("Lolcat this file. Reads from STDIN if missing")
                .takes_value(true)
                .index(1),
        )
        .arg(
            Arg::with_name("help")
                .short("h")
                .long("help")
                .help("Prints help information")
                .takes_value(false),
        )
        .arg(
            Arg::with_name("version")
                .short("V")
                .long("version")
                .help("Prints version information")
                .takes_value(false),
        )
}